#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <math.h>

#include "fuse_impls.h"

static sur_impls* sur_fs = NULL;

void* sdfs_init(struct fuse_conn_info *conn)
{
	LOG("FS init.");
	string srv = GET_STRING("server");
	string usr = GET_STRING("user");
	string pw = GET_STRING("password");
	string ukey_id = GET_STRING("ukey_id");
	string cache = GET_STRING("cache_dir");
	// string srv = "http://127.0.0.1:3322";
	// string usr = "surdoctestooJUvF20@cc.cc";
	// string pw = "aA111111";
	// string cache = "/tmp/";
	
	
	sur_fs = new sur_impls(srv, usr, pw, ukey_id, cache);
	
	if(sur_fs->sur_init() !=0 ) {
		LOG("Mount Filesystem fail when login.");
		exit(1);
	}
	
	return NULL;
}
void sdfs_destroy(void *ptr)
{
	LOG("FS umount.");
	sur_fs->sur_destroy();
	delete sur_fs;
	sur_fs = NULL;
}

int sdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
	filler(buf, ".", NULL, 0);
    filler(buf, "..", NULL, 0);
	
	//list<string> ctx;
	vector<DirEntry> ctx;
	sur_fs->sur_readdir(path, ctx);
	
	vector<DirEntry>::iterator it;
	for(it = ctx.begin(); it != ctx.end(); ++it) {
		struct stat st;
		st.st_nlink 	= 1;
		st.st_size     = (*it).size;
		st.st_blksize  = FS_BLKSIZE;
		st.st_blocks   = ceil(st.st_size/st.st_blksize);
		if((*it).is_folder == true) {
			st.st_mode     = 0755 | S_IFDIR;
		} else {
			st.st_mode     = 0666 | S_IFREG;
		}
		st.st_uid      = 0;
		st.st_gid      = 0;
		st.st_atime    = (*it).mtime;
		st.st_mtime    = (*it).mtime;
		st.st_ctime    = (*it).mtime;
		filler(buf, (*it).name.c_str(), NULL, 0);
	}

	return 0;
	
}
// int sdfs_opendir(const char *path, struct fuse_file_info *fi)
// {
	// LOG("FS opendir %s.", path);
	
	// return 0;
	
// }
// int sdfs_releasedir(const char *path, struct fuse_file_info *fi)
// {
	// LOG("FS releasedir %s.", path);
	
	// return 0;
	
// }
int sdfs_getattr(const char *path, struct stat *st)
{	
	return sur_fs->sur_getattr(path, st);

}
int sdfs_rename(const char *from, const char *to)
{	
	LOG("FS rename %s to %s.", from, to);
	return sur_fs->sur_rename(from, to);
}
int sdfs_unlink(const char *path)
{
	LOG("FS delete %s .", path);
	return sur_fs->sur_unlink(path);
}


int sdfs_open(const char *path, struct fuse_file_info *fi)
{
	LOG("FS open %s.", path);

	fi->fh = (uint64_t)(new sur_fh() );
	return sur_fs->sur_open(path,( fi->flags & O_ACCMODE), (sur_fh*)fi->fh);

}
int sdfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{
	if (size == 0) {
		return 0;
	}

	return sur_fs->sur_read(path, buf, size, offset, (sur_fh*)fi->fh);
}


int sdfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{
	if (size == 0) {
		return 0;
	}

	return sur_fs->sur_write(path, buf, size, offset, (sur_fh*)fi->fh);
}
int sdfs_release (const char *path, struct fuse_file_info *fi)
{
	LOG("FS release %s.", path);

	return sur_fs->sur_release(path, (sur_fh*)fi->fh);
}
int sdfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
{
	LOG("FS create %s.", path);
	fi->fh = (uint64_t)(new sur_fh() );
	return sur_fs->sur_create(path, (sur_fh*)fi->fh);
}
int sdfs_flush(const char *path, struct fuse_file_info *fi)
{
	LOG("FS flush.");
	return sur_fs->sur_flush(path, (sur_fh*)fi->fh);
}

int sdfs_truncate(const char *path, off_t size)
{
	LOG("FS truncate.");
	return sur_fs->sur_truncate(path, size);
}
int sdfs_access(const char *path, int mask)
{
	LOG("FS access.");
	return 0;
}
int sdfs_statfs(const char *path, struct statvfs *st)
{
	LOG("FS statfs.");

	return sur_fs->sur_statfs(st);
}
int sdfs_mkdir(const char *path, mode_t mode)
{
	LOG("FS mkdir.");
	return sur_fs->sur_mkdir(path);
}
int sdfs_rmdir(const char *path)
{
	LOG("FS rmdir %s.", path);
	return sur_fs->sur_rmdir(path);
}
int sdfs_utimens(const char *path, const struct timespec ts[2])
{
	LOG("FS utimes.");
	return 0;
}
int sdfs_chmod(const char *path, mode_t mode)
{
	LOG("FS chmod %s %d.", path, mode);
	return 0;
}
